# 导入必要的库
from wxauto import WeChat  # 微信自动化操作库
import time  # 时间处理
import os  # 操作系统接口
import threading  # 多线程支持
import requests  # HTTP请求库
import json  # JSON数据处理
import sys  # 系统相关操作
import hashlib  # 哈希计算，用于消息去重
from datetime import datetime  # 日期时间处理

class WeChatAIBot:
    """
    微信AI机器人主类
    功能：自动监听微信消息并调用AI大模型进行智能回复
    """
    
    def __init__(self):
        """初始化微信AI机器人"""
        
        # API配置 - 连接DeepSeek大模型的参数
        self.api_config = {
            "api_key": "sk-9f407fd69c17440682d5dcf16edab91b",  # DeepSeek API密钥
            "api_url": "https://api.deepseek.com/v1/chat/completions",  # API接口地址
            "model_name": "deepseek-chat"  # 使用的AI模型名称
        }
        
        # 对话配置 - 控制AI回复的参数
        self.generation_config = {
            "max_tokens": 2000,     # 最大回复长度（token数）
            "temperature": 0.8,     # 回复的随机性（0-1，越高越随机）
            "timeout": 60           # 请求超时时间（秒）
        }
        
        # 系统提示词 - 定义AI助手的性格和行为方式
        self.system_prompt = "你是一个充满激情的19岁台湾女孩，喜欢和人们聊天交朋友。你会用中文和用户交流，并且会用一些有趣的方式来表达自己。每次回复不超过二十个字"
        
        # 微信客户端实例 - 用于操作微信
        self.wx = WeChat()
        
        # 目标好友列表 - 需要自动回复的好友名称列表
        self.target_friends = []
        
        # 对话历史缓存 - 按好友保存的对话记录，用于上下文理解
        self.conversation_history = {}
        
        # 运行状态标志 - 控制监听循环的启停
        self.is_running = False
        
        # 日志文件配置
        self.log_file = "wxauto_logs/wechat_ai_bot.log"
        os.makedirs("wxauto_logs", exist_ok=True)  # 确保日志目录存在
        
    def log_message(self, message, level="INFO"):
        """
        记录日志信息到文件和控制台
        
        参数:
            message (str): 要记录的日志内容
            level (str): 日志级别（INFO/WARNING/ERROR）
        """
        # 获取当前时间戳
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_entry = f"[{timestamp}] [{level}] {message}\n"
        
        # 同时输出到控制台
        print(log_entry.strip())
        
        # 追加写入日志文件
        with open(self.log_file, "a", encoding="utf-8") as f:
            f.write(log_entry)
    
    def get_ai_response(self, user_message, conversation_id=None):
        """
        调用AI大模型API生成智能回复
        
        参数:
            user_message (str): 用户发送的消息内容
            conversation_id (str): 对话标识符（通常为用户名），用于区分不同用户的对话历史
            
        返回:
            str: AI生成的回复内容
        """
        try:
            # 设置HTTP请求头
            headers = {
                'Content-Type': 'application/json',  # 指定发送JSON格式数据
                'Authorization': f'Bearer {self.api_config["api_key"]}'  # 设置API密钥认证
            }
            
            # 构建发送给AI的消息列表
            messages = [{"role": "system", "content": self.system_prompt}]  # 系统提示词
            
            # 如果有对话历史，添加最近10条作为上下文
            if conversation_id and conversation_id in self.conversation_history:
                messages.extend(self.conversation_history[conversation_id][-10:])  # 保留最近10条对话记录
            
            # 添加当前用户消息
            messages.append({"role": "user", "content": user_message})
            
            # 构建请求数据
            data = {
                "model": self.api_config["model_name"],           # AI模型名称
                "messages": messages,                               # 对话消息列表
                "max_tokens": self.generation_config["max_tokens"], # 限制回复长度
                "temperature": self.generation_config["temperature"]  # 控制回复随机性
            }
            
            # 发送请求到AI大模型API
            response = requests.post(
                self.api_config["api_url"],
                headers=headers,
                json=data,
                timeout=self.generation_config["timeout"]
            )
            
            # 处理API响应
            if response.status_code == 200:
                result = response.json()
                ai_reply = result['choices'][0]['message']['content'].strip()
                
                # 保存对话历史到缓存，用于后续上下文理解
                if conversation_id:
                    if conversation_id not in self.conversation_history:
                        self.conversation_history[conversation_id] = []
                    
                    # 添加用户消息和AI回复到对话历史
                    self.conversation_history[conversation_id].extend([
                        {"role": "user", "content": user_message},
                        {"role": "assistant", "content": ai_reply}
                    ])
                
                return ai_reply
            else:
                # API返回错误状态码
                self.log_message(f"API错误: {response.status_code}", "ERROR")
                return "抱歉，我现在无法回复，请稍后再试~"
                
        except requests.exceptions.Timeout:
            # 处理请求超时异常
            self.log_message("请求超时", "ERROR")
            return "网络连接超时，请稍后再试~"
        except Exception as e:
            # 处理其他所有异常
            self.log_message(f"调用AI回复出错: {str(e)}", "ERROR")
            return "宝贝，我在忙工作，稍后回复你哦~❤️"
    
    def add_target_friend(self, friend_name):
        """
        添加要监听的好友到目标列表
        
        参数:
            friend_name (str): 好友的微信昵称
        """
        self.target_friends.append(friend_name)
        self.log_message(f"已添加监听目标: {friend_name}")
    
    def remove_target_friend(self, friend_name):
        """
        从目标列表中移除指定好友
        
        参数:
            friend_name (str): 要移除的好友微信昵称
        """
        if friend_name in self.target_friends:
            self.target_friends.remove(friend_name)
            self.log_message(f"已移除监听目标: {friend_name}")
    
    def set_system_prompt(self, prompt):
        """
        设置AI助手的系统提示词（人设）
        
        参数:
            prompt (str): 系统提示词内容，定义AI的行为方式和性格特征
        """
        self.system_prompt = prompt
        self.log_message("已更新系统提示词")
    
    def load_persona_from_file(self, file_path):
        """
        从文本文件加载AI助手的人设（性格设定）
        
        参数:
            file_path (str): 人设文件的路径
            
        返回:
            bool: 加载成功返回True，失败返回False
        """
        try:
            # 读取人设文件内容
            with open(file_path, 'r', encoding='utf-8') as file:
                persona_content = file.read().strip()
                
            if persona_content:
                # 设置系统提示词为人设内容
                self.set_system_prompt(persona_content)
                self.log_message(f"已加载人设: {os.path.basename(file_path)}")
                return True
            else:
                # 文件内容为空
                self.log_message("人设文件内容为空", "WARNING")
                return False
                
        except Exception as e:
            # 处理文件读取异常
            self.log_message(f"加载人设文件失败: {str(e)}", "ERROR")
            return False
    
    def listen_and_reply(self):
        """
        主监听循环：持续监听微信消息并自动回复
        使用多线程方式运行，避免阻塞主程序
        """
        # 检查是否已设置监听目标
        if not self.target_friends:
            self.log_message("请先添加要监听的好友", "ERROR")
            return
        
        # 设置运行状态为True，启动监听循环
        self.is_running = True
        self.log_message("开始监听微信消息...")
        self.log_message(f"监听目标: {', '.join(self.target_friends)}")
        
        # 使用集合存储已处理消息的哈希值，避免重复处理
        processed_messages = set()
        last_check_time = time.time()
        
        # 主监听循环
        while self.is_running:
            try:
                # 获取微信所有消息
                all_msgs = self.wx.GetAllMessage()
                if not all_msgs:
                    time.sleep(2)  # 没有消息时等待2秒
                    continue
                
                # 获取当前时间戳
                current_time = time.time()
                
                # 存储新消息的列表
                new_messages = []
                
                # 倒序遍历消息（从最新消息开始），提高效率
                for msg_obj in reversed(all_msgs):
                    try:
                        # 统一提取消息信息（支持字典和对象两种格式）
                        if isinstance(msg_obj, dict):
                            # 消息是字典格式
                            sender = msg_obj.get('sender', '') or msg_obj.get('name', '')
                            content = msg_obj.get('content', '') or msg_obj.get('msg', '')
                            timestamp = msg_obj.get('timestamp', current_time)
                        else:
                            # 消息是对象格式
                            sender = getattr(msg_obj, 'sender', '') or getattr(msg_obj, 'name', '')
                            content = getattr(msg_obj, 'content', '') or getattr(msg_obj, 'msg', '')
                            timestamp = getattr(msg_obj, 'timestamp', current_time)
                        
                        # 检查是否是目标好友的消息且内容不为空
                        if sender in self.target_friends and content and content.strip():
                            # 创建消息的唯一标识符（用于去重）
                            # 使用内容和发送者创建唯一标识，确保相同内容的消息只处理一次
                            content_clean = content.strip()
                            # 使用更稳定的哈希方法，避免Python hash()的不稳定性
                            content_hash = hashlib.md5(content_clean.encode('utf-8')).hexdigest()[:8]
                            msg_hash = f"{sender}_{content_hash}"
                            
                            # 判断消息是否为新消息（30秒内且未处理过）
                            # 增加时间窗口到30秒，给微信消息同步更多时间
                            is_recent = current_time - timestamp < 30  # 30秒内的新消息
                            is_new = msg_hash not in processed_messages
                            
                            # 调试日志：记录消息检测信息
                            self.log_message(f"检测到消息 - 发送者: {sender}, 内容长度: {len(content_clean)}, 时间差: {current_time - timestamp:.1f}秒, 哈希: {msg_hash}")
                            
                            if is_recent and is_new:
                                # 添加到新消息列表
                                new_messages.append({
                                    'sender': sender,
                                    'content': content,
                                    'timestamp': timestamp,
                                    'hash': msg_hash
                                })
                                
                                # 限制只处理最新的一条消息，避免消息堆积
                                if len(new_messages) >= 1:
                                    break
                    
                    except Exception as e:
                        # 处理单个消息解析异常，继续处理其他消息
                        continue
                
                # 处理检测到的新消息
                if new_messages:
                    # 按时间排序，确保处理最新的消息
                    new_messages.sort(key=lambda x: x['timestamp'])
                    latest_msg = new_messages[-1]  # 获取最新消息
                    
                    # 标记此消息为已处理，防止重复处理
                    processed_messages.add(latest_msg['hash'])
                    
                    # 记录处理确认
                    self.log_message(f"已确认处理消息: {latest_msg['sender']} - 哈希: {latest_msg['hash']}")
                    
                    # 清理旧的消息记录，避免内存占用过大（保留最近100条）
                    if len(processed_messages) > 100:
                        processed_messages.clear()
                    
                    # 记录收到消息
                    self.log_message(f"收到 {latest_msg['sender']} 的消息: {latest_msg['content']}")
                    
                    # 调用AI生成回复
                    ai_reply = self.get_ai_response(latest_msg['content'], latest_msg['sender'])
                    
                    # 通过微信发送AI回复
                    self.wx.SendMsg(ai_reply)
                    self.log_message(f"回复 {latest_msg['sender']}: {ai_reply}")
                    
                    # 增加延迟，避免过于频繁的回复
                    time.sleep(3)
                
                # 更新检查时间
                last_check_time = current_time
                time.sleep(1)  # 避免CPU占用过高
                
            except KeyboardInterrupt:
                # 处理用户中断（Ctrl+C）
                self.log_message("收到中断信号，停止监听...")
                break
            except Exception as e:
                # 处理监听循环中的其他异常
                self.log_message(f"监听循环出错: {str(e)}", "ERROR")
                time.sleep(3)  # 出错后等待3秒再继续
        
        # 监听循环结束
        self.log_message("已停止监听")
    
    def start_listening(self):
        """
        启动监听线程（异步方式）
        创建后台线程执行监听任务，不阻塞主程序
        """
        if not self.is_running:
            # 创建守护线程，主程序退出时自动结束
            listen_thread = threading.Thread(target=self.listen_and_reply, daemon=True)
            listen_thread.start()
    
    def stop_listening(self):
        """
        停止监听循环
        通过设置is_running=False来优雅地停止监听
        """
        self.is_running = False
        self.log_message("正在停止监听...")
    
    def show_status(self):
        """
        显示当前机器人的运行状态信息
        包括运行状态、监听目标、系统提示词预览等
        """
        print("\n" + "="*50)
        print("微信AI助手状态")
        print("="*50)
        print(f"运行状态: {'运行中' if self.is_running else '已停止'}")
        print(f"监听目标: {', '.join(self.target_friends) if self.target_friends else '无'}")
        print(f"系统提示: {self.system_prompt[:50]}...")  # 显示前50字符
        print(f"日志文件: {self.log_file}")
        print("="*50)

def main():
    """
    程序入口主函数
    负责初始化机器人、配置参数、启动监听等
    """
    # 创建微信AI机器人实例
    bot = WeChatAIBot()
    
    print("微信AI助手启动中...")
    print("请确保微信已登录")
    
    # 交互式添加监听目标好友
    target_friend = input("请输入要监听的好友名称（直接回车跳过）: ").strip()
    if target_friend:
        bot.add_target_friend(target_friend)
    
    # 检查并列出可用的人设文件
    persona_files = ["示例人设_专业助手.txt", "示例人设_可爱助手.txt"]
    for file in persona_files:
        if os.path.exists(file):
            print(f"发现人设文件: {file}")
    
    # 询问是否加载人设文件
    load_persona = input("是否加载人设文件？(y/n): ").strip().lower()
    if load_persona == 'y':
        file_path = input("请输入人设文件路径: ").strip()
        if os.path.exists(file_path):
            bot.load_persona_from_file(file_path)
        else:
            print("文件不存在")
    
    # 显示当前配置状态
    bot.show_status()
    
    # 启动监听循环
    if bot.target_friends:
        try:
            # 直接启动同步监听（阻塞模式）
            bot.listen_and_reply()
        except KeyboardInterrupt:
            # 用户按Ctrl+C中断监听
            bot.stop_listening()
    else:
        # 如果没有设置监听目标，提示用户输入
        print("请至少添加一个监听目标")
        friend_name = input("请输入好友名称: ").strip()
        if friend_name:
            bot.add_target_friend(friend_name)
            bot.listen_and_reply()

# 程序入口点
if __name__ == "__main__":
    main()